﻿/*******************************************************
 * 
 * 作者：胡庆访
 * 创建时间：20100505
 * 说明：差异保存的实现
 * 运行环境：.NET 3.5 SP1
 * 版本号：1.0.0
 * 
 * 历史记录：
 * 创建文件 胡庆访 20100501
 * 抽取出DataClear类。 胡庆访 20100505
 * 
*******************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Csla.Core;
using OpenExpressApp;
using System.Collections;

namespace Csla.OpenExpressApp
{
    /// <summary>
    /// 这是差异保存类的基类，
    /// 
    /// 泛型的意义在于实现静态方法Execute的多态。
    /// </summary>
    /// <typeparam name="TCommand"></typeparam>
    [Serializable]
    public abstract class DiffSaveCommandBase<TCommand> : CommandBase
        where TCommand : DiffSaveCommandBase<TCommand>, new()
    {
        private BusinessBase _diffEntity;

        /// <summary>
        /// 创建一个数据的“清理器”
        /// </summary>
        /// <returns></returns>
        protected abstract IDataClear CreateClear();

        protected override void DataPortal_Execute()
        {
            (this._diffEntity as ISavable).Save();
        }

        public static TCommand Execute(BusinessBase businessBase)
        {
            //清除数据
            var cmd = new TCommand();

            var clear = cmd.CreateClear();

            //清除数据
            cmd._diffEntity = (businessBase as ICloneable).Clone() as BusinessBase;
            clear.ClearData(cmd._diffEntity);

            //保存数据
            cmd = DataPortal.Execute<TCommand>(cmd);

            //整合新旧数据
            clear.MakeOld(businessBase);

            return cmd;
        }
    }

    [Serializable]
    public class DiffSaveCommand : DiffSaveCommandBase<DiffSaveCommand>
    {
        protected override IDataClear CreateClear()
        {
            return new CleanDataClear();
        }
    }

    /// <summary>
    /// 数据清理器
    /// </summary>
    public interface IDataClear
    {
        /// <summary>
        /// 删除不必要的对象，只留下需要保存的数据
        /// </summary>
        /// <param name="businessBase"></param>
        void ClearData(BusinessBase businessBase);

        /// <summary>
        /// 设置对象树的状态为“已保存”。
        /// </summary>
        /// <param name="businessBase"></param>
        void MakeOld(BusinessBase businessBase);
    }

    /// <summary>
    /// 把未修改的数据都清除的清理器
    /// </summary>
    public class CleanDataClear : IDataClear
    {
        public void ClearData(BusinessBase diffEntity)
        {
            var entityInfo = ApplicationModel.GetBusinessObjectInfo(diffEntity.GetType());

            this.ClearDataCore(diffEntity, entityInfo);
        }

        public void MakeOld(BusinessBase oldEntity)
        {
            var entityInfo = ApplicationModel.GetBusinessObjectInfo(oldEntity.GetType());

            this.MakeOldCore(oldEntity, entityInfo);
        }

        /// <summary>
        /// 删除不必要的对象，只留下需要保存的“脏”数据
        /// </summary>
        /// <param name="diffEntity"></param>
        protected virtual void ClearDataCore(BusinessBase diffEntity, BusinessObjectInfo entityInfo)
        {
            foreach (var item in entityInfo.BOsPropertyInfos)
            {
                //如果是懒加载属性，并且没有加载数据时，不需要遍历此属性值
                if (!diffEntity.FieldExists(item.Name)) continue;
                IList childs = diffEntity.GetPropertyValue(item.Name) as IList;
                if (childs == null) continue;

                for (int i = childs.Count - 1; i >= 0; i--)
                {
                    BusinessBase child = childs[i] as BusinessBase;
                    if (!child.IsDirty)
                    {
                        child.NeedCalc = false;
                        (childs as IEditableCollection).RemoveChild(child);
                        ((childs as IEditableCollection).GetDeletedList() as IList).Remove(child);
                        child.NeedCalc = true;
                    }
                    else
                    {
                        ClearData(child as BusinessBase);
                    }
                }
            }
        }

        /// <summary>
        /// 清除子对象集合
        /// </summary>
        /// <param name="oldEntity"></param>
        protected virtual void MakeOldCore(BusinessBase oldEntity, BusinessObjectInfo entityInfo)
        {
            oldEntity.MarkOld();

            foreach (var item in entityInfo.BOsPropertyInfos)
            {
                //如果是懒加载属性，并且没有加载数据时，不需要遍历此属性值
                if (oldEntity.FieldExists(item.Name) == false) continue;

                IList childs = oldEntity.GetPropertyValue(item.Name) as IList;
                if (childs == null) continue;

                //清除已删除数据
                ((childs as IEditableCollection).GetDeletedList() as IList).Clear();

                //所有子对象，都标记为已保存
                for (int i = childs.Count - 1; i >= 0; i--)
                {
                    var child = childs[i] as BusinessBase;
                    if (child.IsDirty || child.IsNew) MakeOld(child);
                }
            }
        }
    }
}